package org.pearl.oauth2.authorizationserverdemo.oauth2;

import lombok.AllArgsConstructor;
import org.pearl.oauth2.authorizationserverdemo.execption.MyWebResponseExceptionTranslator;
import org.pearl.oauth2.authorizationserverdemo.oauth2.sms.SmsCodeGranter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by TD on 2021/7/15
 */
@Configuration
@EnableConfigurationProperties(PearlOauth2Properties.class)
@EnableAuthorizationServer
public class MyAuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    // AuthorizationServer配置
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                // tokenkey这个endpoint当使用JwtToken且使用非对称加密时，资源服务用于获取公钥而开放的，这里指这个 endpoint完全公开
                .tokenKeyAccess("permitAll()")
                // checkToken这个endpoint完全公开
                .checkTokenAccess("permitAll()")
                //  允许表单认证
                .allowFormAuthenticationForClients();
    }


    // 密码解析器
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private AuthenticationManager authenticationManager;
/*    @Autowired
    private TokenStore jwtTokenStore;
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;*/

    @Autowired
    private TokenStore tokenStore;

    @Autowired MyDefaultTokenServices myDefaultTokenServices;

    @Autowired
    MyWebResponseExceptionTranslator myWebResponseExceptionTranslator;

    @Autowired
    UserDetailsService userDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置客户端
        clients
                // 使用内存设置
                .inMemory()
                // client_id
                .withClient("client")
                // client_secret
                .secret(passwordEncoder().encode("secret"))
                // 授权类型: 授权码、刷新令牌、密码、客户端、简化模式、短信验证码 "refresh_token"
                .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "sms_code")
                // 授权范围，也可根据这个范围标识，进行鉴权
                .scopes("admin:org","write:org","read:org")
                .accessTokenValiditySeconds(300)
                .refreshTokenValiditySeconds(3000)
                // 授权码模式 授权页面是否自动授权
                .autoApprove(false)
                .autoApprove("admin:org")
                // 拥有的权限
                .authorities("add:user")
                // 允许访问的资源服务 ID
                //.resourceIds("oauth2-resource-server001-demo")
                // 注册回调地址
                .redirectUris("https://www.baidu.com");
    }

    // 端点配置
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 配置端点允许的请求方式
        endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
        // 配置认证管理器
        endpoints.authenticationManager(authenticationManager);
        // 自定义异常翻译器，用于处理OAuth2Exception
        endpoints.exceptionTranslator(myWebResponseExceptionTranslator);
        // 重新组装令牌颁发者，加入自定义授权模式
        endpoints.tokenGranter(getTokenGranter(endpoints));
/*      // 添加JWT令牌
        // JWT令牌转换器*/
        //endpoints.accessTokenConverter(jwtAccessTokenConverter);
        // JWT 存储令牌
        endpoints.tokenStore(tokenStore);
        // 刷新令牌模式添加 userDetailsService
        endpoints.userDetailsService(userDetailsService);
        // 添加令牌增强器
       endpoints.tokenEnhancer(tokenEnhancer());
        // 是否重用刷新令牌，设置false，每次获取刷新令牌时，都会返回新的刷新令牌
        endpoints.reuseRefreshTokens(false);
        // 修改默认端点路径
        endpoints.pathMapping("/oauth/token","/custom/token");
        // 添加自定义Token Services
        endpoints.tokenServices(myDefaultTokenServices);
    }

    private TokenGranter getTokenGranter(AuthorizationServerEndpointsConfigurer endpoints) {
        // 默认tokenGranter集合
        List<TokenGranter> granters = new ArrayList<>(Collections.singletonList(endpoints.getTokenGranter()));
        // 增加短信验证码模式
        granters.add(new SmsCodeGranter(authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
        // 组合tokenGranter集合
        return new CompositeTokenGranter(granters);
    }
    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new MyTokenEnhancer();
    }
}
// 授权码：http://localhost:20000/oauth/authorize?client_id=client&client_secret=secret&response_type=code
// 授权码获取令牌： http://localhost:20000/oauth/token

// 密码模式：http://localhost:20000/oauth/token

// 简化模式：http://localhost:20000/oauth/authorize?client_id=client&client_secret=secret&response_type=token

// 客户端模式：http://localhost:20000/oauth/token?grant_type=client_credentials


//http://127.0.0.1:9091/oauth/token?client_id=client1&client_secret=123&grant_type=refresh_token&refresh_token=16a423f7-210d-432d-967e-827ff5f54554

// 检查令牌：